
from gpiozero import  DigitalOutputDevice
from gpiozero.pins.pigpio import PiGPIOFactory
import time
import threading

def stepper_worker(stepper):
    stepper.delay = 0.001 # small delay,big speed
    while True:
        if stepper.status==Stepper_Motor.CLOCKWISE:
           stepper.steps_clockwise(stepper.delay,1)
        elif stepper.status==Stepper_Motor.ANTICLOCKWISE:
           stepper.steps_anticlockwise(stepper.delay, 1)
      
class Stepper_Motor:
    # Define stepper motor sequence for full step
    step_seq = [
    [1, 0, 0, 1],
    [1, 0, 0, 0],
    [1, 1, 0, 0],
    [0, 1, 0, 0],
    [0, 1, 1, 0],
    [0, 0, 1, 0],
    [0, 0, 1, 1],
    [0, 0, 0, 1]]

    STOP=0
    STEPS_CLOCKWISE = 1
    STEPS_ANTICLOCKWISE = 2
    CLOCKWISE = 3
    ANTICLOCKWISE = 4

    def __init__(self, IN1, IN2, IN3, IN4):
        self.DICT_CMD_ACTION = {Stepper_Motor.STEPS_CLOCKWISE: self.steps_clockwise,
                                Stepper_Motor.STEPS_ANTICLOCKWISE: self.steps_anticlockwise,
                                Stepper_Motor.STOP: self.stop,
                                Stepper_Motor.CLOCKWISE: self.clockwise,
                                Stepper_Motor.ANTICLOCKWISE:  self.anticlockwise
                                }
        # init
        self.in1= DigitalOutputDevice(pin=IN1,pin_factory=PiGPIOFactory())
        self.in2= DigitalOutputDevice(pin=IN2,pin_factory=PiGPIOFactory())
        self.in3= DigitalOutputDevice(pin=IN3,pin_factory=PiGPIOFactory())
        self.in4= DigitalOutputDevice(pin=IN4,pin_factory=PiGPIOFactory())
        #
        self.status=Stepper_Motor.STOP
        self.delay = 0.001
        self.DEG_PER_STEP = 0.7 # 每一步的角度
   
    def set_step(self,w1, w2, w3, w4):
        self.in1.value=w1
        self.in2.value=w2
        self.in3.value=w3
        self.in4.value=w4
       
    def steps_anticlockwise(self,delay, steps):
        for _ in range(steps):
            for step in Stepper_Motor.step_seq:
                self.set_step(step[0], step[1], step[2], step[3])
                time.sleep(delay)
                if (self.status==Stepper_Motor.STOP):
                   break   
    
    def steps_clockwise(self,delay, steps):
        for _ in range(steps):
            for step in Stepper_Motor.step_seq:
                self.set_step(step[3],step[2], step[1],step[0])
                time.sleep(delay)
                if (self.status==Stepper_Motor.STOP):
                   break   
    
    def clockwise(self):
        self.status=Stepper_Motor.CLOCKWISE 

    def anticlockwise(self):
        self.status=Stepper_Motor.ANTICLOCKWISE     
      
    def stop(self):
        for coil in [self.in4, self.in3, self.in2, self.in1]:
            coil.off()
        self.status=Stepper_Motor.STOP

    def action(self, cmd_to_motor):
        self.degree=5
        self.steps=int(self.degree/self.DEG_PER_STEP)
        if cmd_to_motor==Stepper_Motor.STEPS_CLOCKWISE  or cmd_to_motor==Stepper_Motor.STEPS_ANTICLOCKWISE:
           self.status=cmd_to_motor
           self.DICT_CMD_ACTION[cmd_to_motor](self.delay, self.steps)
        else:
           self.DICT_CMD_ACTION[cmd_to_motor]()      

if __name__ == "__main__":
   stepper=Stepper_Motor(21, 20, 12,25)
   stepper.delay = 0.0005
   stepper.action(Stepper_Motor.STEPS_CLOCKWISE)
   time.sleep(1)
   stepper_thread = threading.Thread(target=stepper_worker, args=(stepper,))
   stepper_thread.start()
   stepper.action(Stepper_Motor.CLOCKWISE)
   time.sleep(5)
   stepper.action(Stepper_Motor.ANTICLOCKWISE)
   time.sleep(5)
   stepper.action(Stepper_Motor.STOP)
   

   
   